/*#include "header.h"
//#include <vector>
using namespace std;*/
#include <vector>
#include <iostream>
#include <regex>

using namespace std;
#include "Preprocessor.h"
#include "typedefs.h"
#include "QueryTree2.h"
#include "QueryTreeTuple.h"

string DIGIT = "\\d";
string LETTER = "[A-Za-z]";
string IDENT = LETTER + "("+ LETTER + "|" + DIGIT + "|#)*";
string designEntity = "(procedure|stmtLst|stmt|assign|call|while|if|variable)";
string INTEGER = DIGIT + "+";
string synonym = IDENT;
string attrName = "(procName|varName|value|stmt#)";
/*string attrRef = synonym + "." + attrName;
string ref = "(\"\\s*"+ IDENT + "\\s*\"|" + INTEGER + "|" + attrRef + ")";
string attrCompare = attrRef + "\\s*=\\s*" + ref;
string attrCond = attrCompare + "(\\s+and\\s+" + attrCompare + ")*";
string entRef = "(" + synonym + "|_|\"" + IDENT + "\"|" + INTEGER + ")";
string stmtRef = "(" + synonym + "|_|"+INTEGER + ")";
string lineRef = "(" + synonym + "|_|" + INTEGER + ")";

string ModifiesP = "Modifies\\s*\\(\\s*" + entRef + "\\s*,\\s*" + entRef + "\\s*\\)";
string ModifiesS = "Modifies\\s*\\(\\s*" + stmtRef + "\\s*,\\s*" + entRef + "\\s*\\)";
string UsesP = "Uses\\s*\\(\\s*" + entRef + "\\s*,\\s*" + entRef + "\\s*\\)";
string UsesS = "Uses\\s*\\(\\s*" + stmtRef + "\\s*,\\s*" + entRef + "\\s*\\)";
string Calls = "Calls\\s*\\(\\s*" + entRef + "\\s*,\\s*" + entRef + "\\s*\\)";
string CallsT = "Calls\\*\\s*\\(\\s*" + entRef + "\\s*,\\s*" + entRef + "\\s*\\)";
string Parent = "Parent\\s*\\(\\s*" + stmtRef + "\\s*,\\s*" + stmtRef + "\\s*\\)";
string ParentT = "Parent\\*\\s*\\(\\s*" + stmtRef + "\\s*,\\s*" + stmtRef + "\\s*\\)";
string Follows = "Follows\\s*\\(\\s*" + stmtRef + "\\s*,\\s*" + stmtRef + "\\s*\\)";
string FollowsT = "Follows\\*\\s*\\(\\s*" + stmtRef + "\\s*,\\s*" + stmtRef + "\\s*\\)";
string Next = "Next\\s*\\(\\s*" + lineRef + "\\s*,\\s*" + lineRef + "\\s*\\)";
string NextT = "Next\\*\\s*\\(\\s*" + lineRef + "\\s*,\\s*" + lineRef + "\\s*\\)";
string Affects = "Affects\\s*\\(\\s*" + lineRef + "\\s*,\\s*" + lineRef + "\\s*\\)";
string AffectsT = "Affects\\*\\s*\\(\\s*" + lineRef + "\\s*,\\s*" + lineRef + "\\s*\\)";
string relRef = "(" + ModifiesP+"|"+ModifiesS+"|"+UsesP+"|"+UsesS+"|"+Calls+"|"+CallsT+"|"+Parent+"|"+ParentT+"|"+Follows+"|"+FollowsT+"|"+Next+"|"+NextT+"|"+Affects+"|"+AffectsT+")";
string relCond = relRef + "(\\s+and\\s+" + relRef + ")*";
string elem = "(" + synonym + "|"+ attrRef+")";
string tuple = "(" + elem + "|<\\s*"+elem+"(\\s*,\\s*" + elem + ")*>)";
string oprtor = "(\\+|-|\\*)";
string sub_expr = synonym + "(\\s*" + oprtor + "\\s*" + synonym + ")*";
string sub_expression = "\"\\s*" + sub_expr + "\\s*\"";
string sub_expression_spec = "_?\\s*" + sub_expression + "\\s*_?";
string assign = synonym +"\\s*\\(\\s*" + entRef + "\\s*,\\s*" + sub_expression_spec + "|_\\s*\\)";
string if_ = synonym +"\\s*\\(\\s*" + entRef + "\\s*,\\s*_,\\s*,\\s*_\\s*\\)";
string while_ = synonym + "\\s*\\(\\s*" + entRef + "\\s*,\\s*_\\s*\\)";
string pattern = "("+assign+"|"+ while_ +"|"+if_+")";
string patternCond = pattern + "(\\s+and\\s+" + pattern + ")*";
string with_cl = "(with\\s+" + attrCond + ")";
string suchthat_cl = "(such\\s+that\\s+" + relCond + ")";
string pattern_cl = "(pattern\\s+" + patternCond + ")";
string declaration = "\\s*" + design_entity + "\\s+" + synonym + "(\\s*,\\s*" + synonym + ")*\\s*;";
string result_cl = "(" + tuple + "|BOOLEAN)";
string select_cl = declaration + "*\\s+Select\\s+" + result_cl + "(\\s+" + with_cl + "\\s*|\\s+" + suchthat_cl + "\\s*|\\s+" + pattern_cl + "\\s*)*\\s*";*/
/*
Preprocessor::Preprocessor() {
}

void Preprocessor::process(string input, QueryTree* tree, vector<Variable>*variables) {
	vector<string>* temp = tokenize(input);
	
}

vector<string>* Preprocessor::tokenize(string input) {
	vector<string>* temp = new vector<string>;
	
	regex Declaration_(declaration);
	regex If_(if_);
	regex While_(while_);
	regex Assign_(assign);
	regex ModifiesP_(ModifiesP);
	regex ModifiesS_(ModifiesS);
	regex UsesP_(UsesP);
	regex UsesS_(UsesS);
	regex Calls_(Calls);
	regex CallsT_(CallsT);
	regex Parent_(Parent);
	regex ParentT_(ParentT);
	regex Follows_(Follows);
	regex FollowsT_(Follows);
	regex Next_(Next);
	regex NextT_(NextT);
	regex Affects_(Affects);
	regex AffectsT_(Affects);

	
	//smatch match;
	regex keywords("\\s*Select\\s+|\\s+such\\s+that\\s+|\\s+with\\s+|\\s+pattern\\s+");
	//sregex_iterator it(input.begin(),input.end(), keywords);
	for (std::sregex_iterator it(input.begin(), input.end(), keywords), end; it != end; ++it) {
		cout <<*it<<endl;
	}

	temp->push_back(input);
	return temp;
}*/

Preprocessor::Preprocessor() {
	symbolTable = new Symbol();
	resultList = new Result();
	relationList = new Relation();
	withList = new WithClause();
}

bool Preprocessor::readChar(vector<string> input, unsigned int* position, char character) {			//need to throw error
	if(input[*position] == *new string() + character) {
		(*position)++;
		return true;
	}
	else {
		//cout<<"invalid syntax."<<endl;
		return false;

	}
}

bool Preprocessor::readDeclaration(vector<string> input, unsigned int* position, string type) {
	do {
		string variableName = input[*position];
	
		if(regex_match(variableName.begin(), variableName.end(), *new regex(synonym))) {
			//insert into symbol table
			SymbolTuple s(toDesign_Entity(type), variableName);
			symbolTable->insertSymbol(&s);
			//cout<<"inserted"<<endl;
			//querytree.add(s); or something like that
			//cout<<"insert into symbol table: "<<variableName<<" type: "<<type<<endl;
		}
		else{
			cout<<"invalid variableName"<<endl;
			return false;
		}
		(*position)++;
		if(input[*position] == ";") {
			(*position)++;
			//return true;
			break;
		}
		else {
			if(!readChar(input, position,',')) {
				return false;
			}
		}
	}while(true);
	//cout<<"returned true.................................."<<endl;
	return true;
}

bool Preprocessor::readResultCl(vector<string>input, unsigned int*position) {
	if(input[*position] == "BOOLEAN") {
		resultList->insertBooleanResult();
		(*position)++;
		//cout<<"insert into result: BOOLEAN"<<endl;
	}
	else if(input[*position] == "<") {
		(*position)++;
		do{
			string variableName = input[*position];
			symbolIndex index=symbolTable->searchSymbolName(variableName);
			if(index != -1) {

				(*position)++;
				if(readChar(input, position, '.')) {
					string attribute = input[*position];
					if(regex_match(attribute.begin(), attribute.end(), *new regex(attrName))) {

						//insert into tree result with attribute
						ResultClauseTuple result(index, toAttrName(attribute));
						resultList->insertResult(&result);
						//cout<<"create result: "<<variableName<<" attribute: "<<attribute<<endl;
					}
					else {
						cout<<"invalid attribute name"<<endl;
						return false;
					}
				}
				else {
					//insert into tree result synonym
					ResultClauseTuple result(index, noAttribute);
					resultList->insertResult(&result);
					//cout<<"create result: "<<variableName<<endl;
					
				}
			}
			else {
				cout<<"query syntax error"<<endl;
				return false;
				break;
			}
			if(input[*position] == ">") {
				(*position)++;
				break;
				//return true;
			}
			else {
				if(!readChar(input, position, ',') ){
					return false;
					//break;
				}

			}

		}while(true);
	}
	else {
			string variableName = input[*position];
			symbolIndex index = symbolTable->searchSymbolName(variableName);
			if(index != -1) {
				//check symbol table whether variableName exist
				
				(*position)++;
				if(readChar(input, position, '.')) {
					string attribute = input[*position];
					if(regex_match(attribute.begin(), attribute.end(), *new regex(attrName))) {

						//insert into tree result with attribute
						ResultClauseTuple result(index, toAttrName(attribute));
						resultList->insertResult(&result);
						//cout<<"create result: "<<variableName<<" attribute: "<<attribute<<endl;
					}
					else {
						cout<<"invalid attribute name"<<endl;
						return false;
					}
				}
				else {
					//insert into tree result synonym
					ResultClauseTuple result(index, noAttribute);
					resultList->insertResult(&result);
					//cout<<"create result: "<<variableName<<endl;
				}
			}
			else {
				cout<<"query syntax error"<<endl;
				return false;
			}
	}
	//(*position)++;
	return true;
}

bool Preprocessor::readSuchThatCl(vector<string>input, unsigned int*position) {
	
	string Relation_regex = "Modifies|Uses|Calls|Calls\\*|Parent|Parent\\*|Follows|Follows\\*|Next|Next\\*|Affects|Affects\\*";
	string name_regex = "\""+IDENT+"\"";
	string number_regex = "\\d+";
	do{
		string relation = input[*position];
		if(regex_match(relation.begin(), relation.end(), *new regex(Relation_regex))) {
			(*position)++;

			if(!readChar(input, position, '(')) {
				return false;
				
				break;				//throw error
			}

			string argument1 = input[*position];

			(*position)++;
			if(!readChar(input, position, ',')) {
				return false;
				break;
			
			}
			
			string argument2 = input[*position];
			(*position)++;

			if(!readChar(input,position, ')')) {
				return false;
				break;
			}

			RelationTuple r(toRelationType(relation));
			bool arg1IsName = regex_match(argument1.begin(), argument1.end(), *new regex(name_regex));
			bool arg1IsNum = regex_match(argument1.begin(), argument1.end(), *new regex(number_regex));
			bool arg1IsSymbol = regex_match(argument1.begin(), argument1.end(), *new regex(synonym));
			bool arg2IsName = regex_match(argument2.begin(), argument2.end(), *new regex(name_regex));
			bool arg2IsNum = regex_match(argument2.begin(), argument2.end(), *new regex(number_regex));
			bool arg2IsSymbol = regex_match(argument2.begin(), argument2.end(), *new regex(synonym));

			if((arg1IsName|arg1IsNum|arg1IsSymbol) == false || (arg2IsName|arg2IsNum|arg2IsSymbol)==false) {
				cout<<"argument error"<<endl;
				return false;
			}
			else {
				if(arg1IsName) {
					r.setArg(argument1.substr(1,argument1.length()-1),1);
				}
				else if(arg1IsNum) {
					r.setArg(atoi(argument1.c_str()),1);
				}
				else {
					symbolIndex index = symbolTable->searchSymbolName(argument1);
					if(index == -1) {
						cout<<"symbol not found"<<endl;
						return false;
					}
					r.setArg(index,1);
				}
				if(arg2IsName) {
					r.setArg(argument2.substr(1,argument2.length()-1),2);
				}
				else if(arg2IsNum) {
					r.setArg(atoi(argument2.c_str()),2);
				}
				else {
					symbolIndex index = symbolTable->searchSymbolName(argument2);
					if(index == -1) {
						cout<<"symbol not found"<<endl;
						return false;
					}
					r.setArg(index,2);
				}			
			}
			relationList->insertRelation(&r);
			//cout<<"create such that "<<relation<<": "<<argument1<<","<<argument2<<endl;

		}
		else{
			cout<<"invalid relation"<<endl;
			return false;
		}
		
		if(input[*position] == "and") 
			(*position)++;
		else break;
	}while(true);
	//(*position)++;
	return true;
}

bool Preprocessor::readWithCl(vector<string>input, unsigned int*position) {
	do {
		string variableName = input[*position];

		symbolIndex index = symbolTable->searchSymbolName(variableName);
		if(index != -1) {
			(*position)++;
			if(readChar(input, position, '.') ){
				string attribute=input[*position];
				if(regex_match(attribute.begin(), attribute.end(), *new regex(attrName))) {
					(*position)++;
					if(readChar(input,position, '=')) {
						string argument = input[*position];
						//create qtree node
						WithClauseTuple w(index,toAttrName(attribute));
						if(regex_match(argument.begin(), argument.end(), *new regex("\\d+"))) {
							w.setRef(atoi(argument.c_str()));
						}
						else
							w.setRef(argument.substr(1,argument.length()-2));
						withList->insertWithClause(&w);
						//cout<<"create with "<<variableName<<"."<<attribute<<"="<<argument<<endl;
						(*position)++;
					}
					else {
						cout<<"= operator expected."<<endl;
						return false;
					}
				}
				else {
					cout<<"invalid attribute Name"<<endl;
					return false;
				}
			}
			else {
				cout<<". operator expected"<<endl;
				return false;
			}
		}
		else {
			cout<<"invalid variable name"<<endl;
			return false;
		}
		if(input[*position] == "and")
			(*position)++;
		else break;
	}while(true);
	return true;
}

bool Preprocessor::readPatternCl(vector<string>input, unsigned int*position) {
	do {
		string variableName = input[*position];

		if(symbolTable->searchSymbolName(variableName) != -1) {
			(*position)++;
			//getType(variableName);
			/*if(readChar(input, position, '(') ){

			}
			else {
				cout<<"\'(\' expected"<<endl;
				return false;
			}*/
		}
		else {
			cout<<"invalid variable name"<<endl;
			return false;
		}
		if(input[*position] == "and")
			(*position)++;
		else break;
	}while(true);
	return true;
}

void Preprocessor::process(string input) {

	vector<string> temp = tokenize(input);
	
	/*for(unsigned int i = 0 ;i<temp.size();i++) {
		cout<<temp[i]<<endl;
	}*/
	bool starting = true;
	for(unsigned int i = 0;i<temp.size();i) {
		//cout<<"loop here"<<endl;
		if(starting) {
			if(regex_match(temp[i].begin(), temp[i].end(), *new regex(designEntity))) {
				string type = temp[i];
				i++;
				//cout<<type<<endl;
				readDeclaration(temp, &i , type);
				continue;
			}
			else if(temp[i] == "select") {
				i++;
				readResultCl(temp, &i);
				starting = false;
				continue;
			}
			else
				cout<<"syntax error";
		}
		else {
			if(temp[i] == "such that") {
				i++;
				readSuchThatCl(temp, &i);
				continue;
			}
			if(temp[i] == "with") {
				i++;
				readWithCl(temp, &i);
				continue;
			}
			if(temp[i] == "pattern") {
				i++;
				readPatternCl(temp, &i);
				continue;
			}

		}
		if(temp[i] == "end") {
			//cout<<"ended"<<endl;
			break;
		}

	}
	
	/*cout<<"Symbol table: "<<endl;
	for(int i = 0;i<symbolTable->getSize();i++) {
		cout<<symbolTable->getSymbolName(i)<<endl;
	}
	cout<<endl;
	cout<<"Result table: "<<endl;
	vector<ResultClauseTuple> allResult = resultList->getAllResult();
	for(int i = 0;i<allResult.size();i++ ){
		cout<<allResult[i].getSymbolIndex()<<endl;
	}*/


}

vector<string> Preprocessor::tokenize(string input) {
	string builder;
	vector<string> temp;

	input  = input + '\n';
	
	for (unsigned int i = 0;i < input.length();i++) {
		if(input[i] == ' ' || input[i] == '\n') {
			if(builder != "") {
				if(builder == "that" && temp.back() == "such") {
					builder = temp.back() + " " + builder;
					temp.pop_back();
				}
				
				temp.push_back(builder);
				builder = "";
				
			}
			continue;
		}
		if(input[i] == '(' || input[i] == ')' || input[i] == '<' || input[i] == '>' || input[i] == ';' || input[i] == ',' || input[i] == '=' || input[i] == '.') {
			if(builder != "") {
				temp.push_back(builder);
				builder = "";
			}

			temp.push_back(*new string() + input[i]);
			continue;
		}

		builder = builder + input[i];
	
	}
	
	temp.push_back("end");
	return temp;
}

Symbol* Preprocessor::getSymbolTable() {
	return symbolTable;
}

Result* Preprocessor::getResultList() {
	return resultList;
}

Relation* Preprocessor::getRelationList() {
	return relationList;
}

WithClause* Preprocessor::getWithList() {
	return withList;
}
